#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<errno.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<unistd.h>
#include "DES.c"

#define MAXLINE 4096

int K_client[64] = { 1, 0, 1, 1, 0, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0,
                     0, 0, 1, 1, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0 };

int K_tgs[64] = {1, 0, 1, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0,
                 0, 0, 0, 1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1 };

int K_ss[64] = {0, 0, 1, 0, 1, 1, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0,
                1, 1, 1, 0, 0, 1, 1, 1, 0, 1, 1, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 1 };

char K_client_ss[65] = "0101010110101010010100110000111111001010001100111011001010010011";

int size;
char inputTexts[100][65];
int input[100][64];

char TGSsendC[4096];
char TGSsendD[4096];
char TGSsendE[4096];
char TGSsendF[4096];


//消息E
char clientAdr[9] = "11100000";
char validity[6] = "11011";


void intToString(int a[][64], int size, char* sendline) {
    int index = 0;
    for (int i = 0; i < size; ++i) {
        for (int j = 0; j < 64; ++j) {
            sendline[index++] = a[i][j] + 48;
        }
    }
    sendline[index] = '\0';
}


int main(int argc, char** argv){
    int  listenfd, connfd;    
    struct sockaddr_in  servaddr;
    char  buff[4096];
    int  n;
    if( (listenfd = socket(AF_INET, SOCK_STREAM, 0)) == -1 ){
        printf("create socket error: %s(errno: %d)\n",strerror(errno),errno);
        return 0;
   }

    memset(&servaddr, 0, sizeof(servaddr));
    servaddr.sin_family = AF_INET;
    servaddr.sin_addr.s_addr = inet_addr("127.0.0.1");
    servaddr.sin_port = htons(8081);

    if(bind(listenfd, (struct sockaddr*)&servaddr, sizeof(servaddr)) == -1){
        printf("bind socket error: %s(errno: %d)\n",strerror(errno),errno);
        return 0;
    }

    if(listen(listenfd, 10) == -1){
        printf("listen socket error: %s(errno: %d)\n",strerror(errno),errno);
        return 0;
    }

    printf("======waiting for client's request======\n");
    while(1){
        //accept发生阻塞
        if((connfd = accept(listenfd, (struct sockaddr*)NULL, NULL)) == -1){
            printf("accept socket error: %s(errno: %d)",strerror(errno),errno);
            continue;
        }
        n = recv(connfd, TGSsendC, MAXLINE, 0);
        TGSsendC[n] = '\0';
        printf("消息C: %s\n", TGSsendC);

        n = recv(connfd, TGSsendD, MAXLINE, 0);
        TGSsendD[n] = '\0';
        printf("消息D: %s\n", TGSsendD);



        //从消息C中提取消息B
        char cipherB[4096];
        for (int i = 8; i < strlen(TGSsendC); ++i) {
            cipherB[i-8] = TGSsendC[i];
        }

        cipherB[strlen(TGSsendC)-8] = '\0';

        //对消息B进行解密
        int cipherBInt[100][64];
        int plainB[100][64];
        for (int i = 0; i < strlen(cipherB); ++i) {
            int k = i / 64;
            int j = i % 64;
            cipherBInt[k][j] = cipherB[i] - 48;
        } 

        int sizeB = strlen(cipherB) / 64;
        for (int i = 0; i < sizeB; ++i) {
            decrypt(cipherBInt[i], K_tgs, plainB[i]);
        }   

        int k_client_tgs[64];
        for (int i = 16; i < 64; ++i) {
            k_client_tgs[i-16] = plainB[0][i];
        }

        for (int i = 0; i < 16; ++i) {
            k_client_tgs[i+48] = plainB[1][i];
        }


        //运用K_client_tags对消息D进行解密
        int cipherDInt[100][64];
        int plainD[100][64];
        for (int i = 0; i < strlen(TGSsendD); ++i) {
            int k = i / 64;
            int j = i % 64;
            cipherDInt[k][j] = TGSsendD[i] - 48;
        } 

        int sizeD = strlen(TGSsendD) / 64;
        for (int i = 0; i < sizeD; ++i) {
            decrypt(cipherDInt[i], k_client_tgs, plainD[i]);
        } 

        //serviceID，从消息C中提取
        char serviceID[9];
        for (int i = 0; i < 8; ++i) {
            serviceID[i] = TGSsendC[i];
        }
        serviceID[8] = '\0';

        //clientID
        char clientID[4];
        for (int i = 0; i < 3; ++i) {
            clientID[i] = plainD[0][i] + 48;
        }
        clientID[3] = '\0';

        //timestamp
        char timestamp[6];
        for (int i = 0; i < 5; ++i) {
            timestamp[i] = plainD[0][i+3] + 48;
        } 
        timestamp[5] = '\0';


        //消息E
        char textST[4096];
        strncat(textST, clientID, 4);
        strncat(textST, clientAdr, 9);
        strncat(textST, validity, 6);
        strncat(textST, K_client_ss, 65);

        //ST
        for (int i = 0; i < 64; ++i) {
            inputTexts[0][i] = textST[i];
        }
        for (int i = 0; i < 16; ++i) {
            inputTexts[1][i] = textST[i+64];
        }

        size = 2;
        manageText();
        int cipherST[size][64];
        for (int i = 0; i < size; ++i) {
            encrypt(input[i], K_ss, cipherST[i]);
        }
        char ST[4096];
        intToString(cipherST, size, ST);    

        strncat(TGSsendE, serviceID, 9);
        strncat(TGSsendE, ST, strlen(ST));
        TGSsendE[strlen(ST)+8] = '\0';

        //消息F
        for (int i = 0; i < 64; ++i) {
            inputTexts[0][i] = K_client_ss[i];
        }

        size = 1;
        manageText();

        int cipherF[size][64];
        for (int i = 0; i < size; ++i) {
            encrypt(input[i], k_client_tgs, cipherF[i]);
        }

        intToString(cipherF, size, TGSsendF);


        //发送消息E和消息F
        printf("======发送消息E和消息F给client======\n");
        printf("消息E: %s\n", TGSsendE);
        printf("消息F: %s\n", TGSsendF);
        if(send(connfd, TGSsendE, strlen(TGSsendE), 0) < 0){
            printf("send msg error: %s(errno: %d)\n", strerror(errno), errno);
        }
        sleep(2);

        if(send(connfd, TGSsendF, strlen(TGSsendF), 0) < 0){
            printf("send msg error: %s(errno: %d)\n", strerror(errno), errno);
        }


        close(connfd);


    }

    close(listenfd);
    return 0;
}